react组件通讯

组件父子

组件数据父传子

React数据流动是单向的

父组件通过向子组件传递 props,子组件得到 props 后进行相应的处理。

父组件 Parent.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { Component } from "react";
import Child from "./Child";

class Parent extends Component {
constructor(props) {
super(props);
this.state = {
mess: "来自父组件的消息"
};
}
render() {
return (
<div>
<h1>父组件</h1>
{/* 在子组件上自定义属性名称传递数据 */}
<Child sendSonData={this.state.mess}/>
</div>
);
}
}

export default Parent;

子组件 Child.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React, { Component } from "react";

class Child extends Component {
render() {
return (
<div>
<h2>子组件</h2>
{/* 子组件通过 props 项接收父组件传递过来的参数 */}
<span>{this.props.sendSonData}</span>
</div>
);
}
}

export default Child;

页面显示效果

images

组件数据子传父

利用回调函数,可以实现子组件向父组件通信:父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,便可以向父组件通信。

子组件 Child.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { Component } from "react";

class Child extends Component {
constructor(...args) {
super(...args);
this.state = {
mess: "来自子组件的消息"
};
}
render() {
return (
<div>
<h2>子组件</h2>
<button onClick={this.props.sendParentData.bind(null, this.state.mess)}>
子按钮
</button>
</div>
);
}
}

export default Child;

父组件 Parent.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import React, { Component } from "react";
import Child from "./Child";

class Parent extends Component {
constructor(...args) {
super(...args);
this.state = {
mess: ""
};
}
childFn=(data)=> {
this.setState({
mess: data
});
}
render() {
return (
<div>
<h1>父组件</h1>
<span>{this.state.mess}</span>
<Child sendParentData={this.childFn} />
</div>
);
}
}

export default Parent;

页面显示效果

images

跨级组件通信

所谓跨级组件通信,就是父组件向子组件的子组件通信,向更深层的子组件通信。跨级组件通信可以采用下面两种方式:

  • 中间组件层层传递 props
  • 使用 context 对象

对于第一种方式,如果父组件结构较深,那么中间的每一层组件都要去传递 props,增加了复杂度,并且这些 props 并不是这些中间组件自己所需要的。不过这种方式也是可行的,当组件层次在三层以内可以采用这种方式,当组件嵌套过深时,采用这种方式就需要斟酌了。

使用 context 是另一种可行的方式,context 相当于一个全局变量,是一个大容器,我们可以把要通信的内容放在这个容器中,这样一来,不管嵌套有多深,都可以随意取用。
使用 context 也很简单,需要满足两个条件:

  • 上级组件要声明自己支持 context,并提供一个函数来返回相应的 context 对象
  • 子组件要声明自己需要使用 context

组件数据父传孙

父组件 parent.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import React, { Component } from "react";
import PropTypes from "prop-types";
import Child from "./Child";

class Parent extends Component {
constructor(...args) {
super(...args);
this.state = {
message: "来自父组件的消息"
};
}
// 父组件声明自己支持 context
static childContextTypes = {
// PropTypes 验证,必须为 String
message: PropTypes.string
};

// 父组件提供一个函数,用来返回相应的 context 对象
getChildContext() {
return {
message: this.state.message
};
}
render() {
return (
<div>
<h1>父组件</h1>
<Child/>
</div>
);
}
}

export default Parent;

子组件 Child.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React, { Component } from "react";
import SubChild from './SubChild'

class Child extends Component {
render() {
return (
<div>
<h2>子组件</h2>
<SubChild/>
</div>
);
}
}

export default Child;

孙组件 subChild.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { Component } from "react";
import PropTypes from "prop-types";

class SubChild extends Component {
// 子组件声明自己需要使用 context
static contextTypes = {
message: PropTypes.string
};
render() {
return (
<div>
<h3>孙组件</h3>
{this.context.message}
</div>
);
}
}

export default SubChild;

页面显示效果

images

组件数据孙传父

父组件 Parent.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import React, { Component } from "react";
import PropTypes from "prop-types";
import Child from "./Child";

class Parent extends Component {
constructor(...args) {
super(...args);
this.state = {
msg: ""
};
}
// 父组件声明自己支持 context
static childContextTypes = {
// PropTypes 验证,必须为 function
callback: PropTypes.func
};

// 父组件提供一个函数,用来返回相应的 context 对象
getChildContext() {
return {
callback: this.callback
};
}
callback = msg => {
this.setState({
msg: msg
});
};
render() {
return (
<div>
<h1>父组件</h1>
<span>{this.state.msg}</span>
<Child />
</div>
);
}
}

export default Parent;

子组件 Child.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React, { Component } from "react";
import SubChild from './SubChild'

class Child extends Component {
render() {
return (
<div>
<h2>子组件</h2>
<SubChild/>
</div>
);
}
}

export default Child;

孙组件 SubChild.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { Component } from "react";
import PropTypes from "prop-types";

class SubChild extends Component {
// 子组件声明自己需要使用 context
static contextTypes = {
callback:PropTypes.func
};
render() {
return (
<div>
<h3>孙组件</h3>
<button onClick = { ()=>this.context.callback('来自孙组件的消息') }>点击我</button>
</div>
);
}
}

export default SubChild;

页面显示效果

images

如果是父组件向子组件单向通信,可以使用变量,如果子组件想向父组件通信,同样可以由父组件提供一个回调函数,供子组件调用,回传参数。
在使用 context 时,有两点需要注意:

  • 父组件需要声明自己支持 context,并提供 context 中属性的 PropTypes
  • 子组件需要声明自己需要使用 context,并提供其需要使用的 context 属性的 PropTypes
  • 父组件需提供一个 getChildContext 函数,以返回一个初始的 context 对象

如果组件中使用构造函数(constructor),还需要在构造函数中传入第二个参数 context,并在 super 调用父类构造函数是传入 context,否则会造成组件中无法使用 context

改变 context 对象

不应该也不能直接改变 context 对象中的属性,要想改变 context 对象,只有让其和父组件的 state 或者 props 进行关联,在父组件的 stateprops 变化时,会自动调用 getChildContext 方法,返回新的 context 对象,而后子组件进行相应的渲染。

createContext

在 16.4.1 之后,context api 遭到废弃,启用新的 createContext api

Context 的使用基于生产者消费者模式

Context.js

1
2
3
4
5
import React from "react";

export const DemoContext = React.createContext({
num:1,
});

Parent.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, {Component} from "react";
import Child from "./Child";
import {DemoContext} from "./Context.js"

class Parent extends Component {
constructor(...args) {
super(...args);
this.state = {
num:1,
};
}

fn = ()=>{
const {num} = this.state;
const temp = num +1;
this.setState({
num:temp
})
}

render() {
const {num} = this.state;
return (
<DemoContext.Provider value={{num}}>
<h1 onClick={this.fn}>父组件点击</h1>
<Child/>
</DemoContext.Provider>
);
}
}

export default Parent;

Child.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React, {Component} from "react";
import SubChild from './SubChild'

class Child extends Component {
render() {
return (
<div>
<h2>子组件</h2>
<SubChild/>
</div>
);
}
}

export default Child;

SubChild.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { Component } from "react";
import { DemoContext } from "./Context.js";

class SubChild extends Component {
render() {
return (
<DemoContext.Consumer>
// 此处只能是 function ,如果子组件的 state 需要,可将 context 传递过去 {...context} ,在子组件使用 this.props 获取 context。
{context => (
<div>
<h3>{context.num}</h3>
</div>
)}
</DemoContext.Consumer>
);
}
}

export default SubChild;

非嵌套组件间通信

本文结束,感谢您的阅读